import config from "../../config";
import {EnumDirection} from "../../enum/enumPosition";
import audio from "../../service/audio";

/**
 * 抽象类
 */
export default abstract class AbstractModel {
    // 宽度,碰撞判断需要跨模型调用，所以为public
    public width = config.model.common.width;
    // 高度,碰撞判断需要跨模型调用，所以为public
    public height = config.model.common.height;
    // 抽象属性：模型名称
    abstract name: string
    // 抽象属性：画布实例
    abstract canvas: ICanvas
    // 方向,子弹的方向取决于坦克的方向，需要同层级调用
    public direction: EnumDirection = EnumDirection.top

    //构造函数渲染
    // 碰撞判断需要跨模型调用模型的坐标位置，所以为public
    constructor(
        public x: number,
        public y: number
    ) {
        // 方向随机生成
        this.randomDirection();
    }

    // 抽象方法:渲染贴图
    abstract render(): void

    // 抽象方法:获取贴图
    abstract getImage(): HTMLImageElement

    // 方向随机生成
    randomDirection(): void {
        // 随机取一个
        const index = Math.floor((Math.random() * 4))
        // 存储方向
        this.direction = Object.keys(EnumDirection)[index] as EnumDirection
    }

    // 函数：卸载（移除）模型
    public destroy(): void {
        // 让画布将模型移除掉
        this.canvas.removeModel(this)
        // 重新渲染画布
        this.canvas.renderModels()
    }

    // 函数:渲染模型
    protected draw(): void {
        this.canvas.ctx.drawImage(
            this.getImage(),
            this.x,
            this.y,
            config.model.common.width,
            config.model.common.height
        )
    }

    /**
     * 爆炸效果实现
     * 原理：8张gif图片依次切换显示。
     * @param model 被打炸的模型
     * @protected
     */
    protected blast(model: IModel) {
        // 爆炸的声音
        audio.blast()
        //生成0-7的数组
        let list = Array(...Array(8).keys())
        // console.log(list)

        // 一个Promise调用完，再调用另一个Promise
        // 图片是异步加载的
        //Array.reduce 接收一个函数作为累加器，数组中的每个值（从左到右）开始缩减，最终计算为一个值。
        // 第一个参数为function(total,currentValue, index,arr)
        // total 必需。初始值, 或者计算结束后的返回值。
        //     currentValue	必需。当前元素
        //     currentIndex	可选。当前元素的索引
        //     arr	可选。当前元素所属的数组对象。
        // 第二个参数为传递给函数的初始值

        list.reduce((promise, index) => {
            return new Promise(resolve => {
                // 定时器，每个图片的切换都有一定的延时
                setTimeout(() => {
                    const img = new Image
                    img.src = `src/static/images/blasts/blast${index}.gif`
                    // 图片加载完毕的监听方法
                    img.onload = () => {
                        //渲染图片
                        this.canvas.ctx.drawImage(img, model.x, model.y, model.width, model.height)
                        // 跳出结束Promise
                        resolve(promise)
                    }
                }, 60)
            })
            // @ts-ignore
        }, Promise.resolve()).then(promise => {
        })
    }
}
